; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s

; Test that basic 128-bit integer operations assemble as expected.

target triple = "wasm32-unknown-unknown"

declare i128 @llvm.ctlz.i128(i128, i1)
declare i128 @llvm.cttz.i128(i128, i1)
declare i128 @llvm.ctpop.i128(i128)

define i128 @add128(i128 %x, i128 %y) {
; CHECK-LABEL: add128:
; CHECK:         .functype add128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push8=, 0
; CHECK-NEXT:    local.get $push7=, 1
; CHECK-NEXT:    local.get $push6=, 3
; CHECK-NEXT:    i64.add $push5=, $pop7, $pop6
; CHECK-NEXT:    local.tee $push4=, 3, $pop5
; CHECK-NEXT:    i64.store 0($pop8), $pop4
; CHECK-NEXT:    local.get $push13=, 0
; CHECK-NEXT:    local.get $push10=, 2
; CHECK-NEXT:    local.get $push9=, 4
; CHECK-NEXT:    i64.add $push0=, $pop10, $pop9
; CHECK-NEXT:    local.get $push12=, 3
; CHECK-NEXT:    local.get $push11=, 1
; CHECK-NEXT:    i64.lt_u $push1=, $pop12, $pop11
; CHECK-NEXT:    i64.extend_i32_u $push2=, $pop1
; CHECK-NEXT:    i64.add $push3=, $pop0, $pop2
; CHECK-NEXT:    i64.store 8($pop13), $pop3
; CHECK-NEXT:    return
  %a = add i128 %x, %y
  ret i128 %a
}

define i128 @sub128(i128 %x, i128 %y) {
; CHECK-LABEL: sub128:
; CHECK:         .functype sub128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push7=, 0
; CHECK-NEXT:    local.get $push6=, 1
; CHECK-NEXT:    local.get $push5=, 3
; CHECK-NEXT:    i64.sub $push0=, $pop6, $pop5
; CHECK-NEXT:    i64.store 0($pop7), $pop0
; CHECK-NEXT:    local.get $push12=, 0
; CHECK-NEXT:    local.get $push9=, 2
; CHECK-NEXT:    local.get $push8=, 4
; CHECK-NEXT:    i64.sub $push1=, $pop9, $pop8
; CHECK-NEXT:    local.get $push11=, 1
; CHECK-NEXT:    local.get $push10=, 3
; CHECK-NEXT:    i64.lt_u $push2=, $pop11, $pop10
; CHECK-NEXT:    i64.extend_i32_u $push3=, $pop2
; CHECK-NEXT:    i64.sub $push4=, $pop1, $pop3
; CHECK-NEXT:    i64.store 8($pop12), $pop4
; CHECK-NEXT:    return
  %a = sub i128 %x, %y
  ret i128 %a
}

define i128 @mul128(i128 %x, i128 %y) {
; CHECK-LABEL: mul128:
; CHECK:         .functype mul128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push4=, __stack_pointer
; CHECK-NEXT:    i32.const $push5=, 16
; CHECK-NEXT:    i32.sub $push9=, $pop4, $pop5
; CHECK-NEXT:    local.tee $push8=, 5, $pop9
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    local.get $push10=, 4
; CHECK-NEXT:    call __multi3, $pop14, $pop13, $pop12, $pop11, $pop10
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push0=, 8
; CHECK-NEXT:    i32.add $push1=, $pop15, $pop0
; CHECK-NEXT:    i64.load $push2=, 0($pop1)
; CHECK-NEXT:    i64.store 8($pop16), $pop2
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push3=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop3
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.add $push7=, $pop19, $pop6
; CHECK-NEXT:    global.set __stack_pointer, $pop7
; CHECK-NEXT:    return
  %a = mul i128 %x, %y
  ret i128 %a
}

define i128 @sdiv128(i128 %x, i128 %y) {
; CHECK-LABEL: sdiv128:
; CHECK:         .functype sdiv128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push4=, __stack_pointer
; CHECK-NEXT:    i32.const $push5=, 16
; CHECK-NEXT:    i32.sub $push9=, $pop4, $pop5
; CHECK-NEXT:    local.tee $push8=, 5, $pop9
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    local.get $push10=, 4
; CHECK-NEXT:    call __divti3, $pop14, $pop13, $pop12, $pop11, $pop10
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push0=, 8
; CHECK-NEXT:    i32.add $push1=, $pop15, $pop0
; CHECK-NEXT:    i64.load $push2=, 0($pop1)
; CHECK-NEXT:    i64.store 8($pop16), $pop2
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push3=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop3
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.add $push7=, $pop19, $pop6
; CHECK-NEXT:    global.set __stack_pointer, $pop7
; CHECK-NEXT:    return
  %a = sdiv i128 %x, %y
  ret i128 %a
}

define i128 @udiv128(i128 %x, i128 %y) {
; CHECK-LABEL: udiv128:
; CHECK:         .functype udiv128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push4=, __stack_pointer
; CHECK-NEXT:    i32.const $push5=, 16
; CHECK-NEXT:    i32.sub $push9=, $pop4, $pop5
; CHECK-NEXT:    local.tee $push8=, 5, $pop9
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    local.get $push10=, 4
; CHECK-NEXT:    call __udivti3, $pop14, $pop13, $pop12, $pop11, $pop10
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push0=, 8
; CHECK-NEXT:    i32.add $push1=, $pop15, $pop0
; CHECK-NEXT:    i64.load $push2=, 0($pop1)
; CHECK-NEXT:    i64.store 8($pop16), $pop2
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push3=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop3
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.add $push7=, $pop19, $pop6
; CHECK-NEXT:    global.set __stack_pointer, $pop7
; CHECK-NEXT:    return
  %a = udiv i128 %x, %y
  ret i128 %a
}

define i128 @srem128(i128 %x, i128 %y) {
; CHECK-LABEL: srem128:
; CHECK:         .functype srem128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push4=, __stack_pointer
; CHECK-NEXT:    i32.const $push5=, 16
; CHECK-NEXT:    i32.sub $push9=, $pop4, $pop5
; CHECK-NEXT:    local.tee $push8=, 5, $pop9
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    local.get $push10=, 4
; CHECK-NEXT:    call __modti3, $pop14, $pop13, $pop12, $pop11, $pop10
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push0=, 8
; CHECK-NEXT:    i32.add $push1=, $pop15, $pop0
; CHECK-NEXT:    i64.load $push2=, 0($pop1)
; CHECK-NEXT:    i64.store 8($pop16), $pop2
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push3=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop3
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.add $push7=, $pop19, $pop6
; CHECK-NEXT:    global.set __stack_pointer, $pop7
; CHECK-NEXT:    return
  %a = srem i128 %x, %y
  ret i128 %a
}

define i128 @urem128(i128 %x, i128 %y) {
; CHECK-LABEL: urem128:
; CHECK:         .functype urem128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push4=, __stack_pointer
; CHECK-NEXT:    i32.const $push5=, 16
; CHECK-NEXT:    i32.sub $push9=, $pop4, $pop5
; CHECK-NEXT:    local.tee $push8=, 5, $pop9
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    local.get $push10=, 4
; CHECK-NEXT:    call __umodti3, $pop14, $pop13, $pop12, $pop11, $pop10
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push0=, 8
; CHECK-NEXT:    i32.add $push1=, $pop15, $pop0
; CHECK-NEXT:    i64.load $push2=, 0($pop1)
; CHECK-NEXT:    i64.store 8($pop16), $pop2
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push3=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop3
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.add $push7=, $pop19, $pop6
; CHECK-NEXT:    global.set __stack_pointer, $pop7
; CHECK-NEXT:    return
  %a = urem i128 %x, %y
  ret i128 %a
}

define i128 @and128(i128 %x, i128 %y) {
; CHECK-LABEL: and128:
; CHECK:         .functype and128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push4=, 0
; CHECK-NEXT:    local.get $push3=, 2
; CHECK-NEXT:    local.get $push2=, 4
; CHECK-NEXT:    i64.and $push0=, $pop3, $pop2
; CHECK-NEXT:    i64.store 8($pop4), $pop0
; CHECK-NEXT:    local.get $push7=, 0
; CHECK-NEXT:    local.get $push6=, 1
; CHECK-NEXT:    local.get $push5=, 3
; CHECK-NEXT:    i64.and $push1=, $pop6, $pop5
; CHECK-NEXT:    i64.store 0($pop7), $pop1
; CHECK-NEXT:    return
  %a = and i128 %x, %y
  ret i128 %a
}

define i128 @or128(i128 %x, i128 %y) {
; CHECK-LABEL: or128:
; CHECK:         .functype or128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push4=, 0
; CHECK-NEXT:    local.get $push3=, 2
; CHECK-NEXT:    local.get $push2=, 4
; CHECK-NEXT:    i64.or $push0=, $pop3, $pop2
; CHECK-NEXT:    i64.store 8($pop4), $pop0
; CHECK-NEXT:    local.get $push7=, 0
; CHECK-NEXT:    local.get $push6=, 1
; CHECK-NEXT:    local.get $push5=, 3
; CHECK-NEXT:    i64.or $push1=, $pop6, $pop5
; CHECK-NEXT:    i64.store 0($pop7), $pop1
; CHECK-NEXT:    return
  %a = or i128 %x, %y
  ret i128 %a
}

define i128 @xor128(i128 %x, i128 %y) {
; CHECK-LABEL: xor128:
; CHECK:         .functype xor128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push4=, 0
; CHECK-NEXT:    local.get $push3=, 2
; CHECK-NEXT:    local.get $push2=, 4
; CHECK-NEXT:    i64.xor $push0=, $pop3, $pop2
; CHECK-NEXT:    i64.store 8($pop4), $pop0
; CHECK-NEXT:    local.get $push7=, 0
; CHECK-NEXT:    local.get $push6=, 1
; CHECK-NEXT:    local.get $push5=, 3
; CHECK-NEXT:    i64.xor $push1=, $pop6, $pop5
; CHECK-NEXT:    i64.store 0($pop7), $pop1
; CHECK-NEXT:    return
  %a = xor i128 %x, %y
  ret i128 %a
}

define i128 @shl128(i128 %x, i128 %y) {
; CHECK-LABEL: shl128:
; CHECK:         .functype shl128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push5=, __stack_pointer
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.sub $push10=, $pop5, $pop6
; CHECK-NEXT:    local.tee $push9=, 5, $pop10
; CHECK-NEXT:    global.set __stack_pointer, $pop9
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    i32.wrap_i64 $push0=, $pop11
; CHECK-NEXT:    call __ashlti3, $pop14, $pop13, $pop12, $pop0
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push1=, 8
; CHECK-NEXT:    i32.add $push2=, $pop15, $pop1
; CHECK-NEXT:    i64.load $push3=, 0($pop2)
; CHECK-NEXT:    i64.store 8($pop16), $pop3
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push4=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop4
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push7=, 16
; CHECK-NEXT:    i32.add $push8=, $pop19, $pop7
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    return
  %a = shl i128 %x, %y
  ret i128 %a
}

define i128 @shr128(i128 %x, i128 %y) {
; CHECK-LABEL: shr128:
; CHECK:         .functype shr128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push5=, __stack_pointer
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.sub $push10=, $pop5, $pop6
; CHECK-NEXT:    local.tee $push9=, 5, $pop10
; CHECK-NEXT:    global.set __stack_pointer, $pop9
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    i32.wrap_i64 $push0=, $pop11
; CHECK-NEXT:    call __lshrti3, $pop14, $pop13, $pop12, $pop0
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push1=, 8
; CHECK-NEXT:    i32.add $push2=, $pop15, $pop1
; CHECK-NEXT:    i64.load $push3=, 0($pop2)
; CHECK-NEXT:    i64.store 8($pop16), $pop3
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push4=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop4
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push7=, 16
; CHECK-NEXT:    i32.add $push8=, $pop19, $pop7
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    return
  %a = lshr i128 %x, %y
  ret i128 %a
}

define i128 @sar128(i128 %x, i128 %y) {
; CHECK-LABEL: sar128:
; CHECK:         .functype sar128 (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push5=, __stack_pointer
; CHECK-NEXT:    i32.const $push6=, 16
; CHECK-NEXT:    i32.sub $push10=, $pop5, $pop6
; CHECK-NEXT:    local.tee $push9=, 5, $pop10
; CHECK-NEXT:    global.set __stack_pointer, $pop9
; CHECK-NEXT:    local.get $push14=, 5
; CHECK-NEXT:    local.get $push13=, 1
; CHECK-NEXT:    local.get $push12=, 2
; CHECK-NEXT:    local.get $push11=, 3
; CHECK-NEXT:    i32.wrap_i64 $push0=, $pop11
; CHECK-NEXT:    call __ashrti3, $pop14, $pop13, $pop12, $pop0
; CHECK-NEXT:    local.get $push16=, 0
; CHECK-NEXT:    local.get $push15=, 5
; CHECK-NEXT:    i32.const $push1=, 8
; CHECK-NEXT:    i32.add $push2=, $pop15, $pop1
; CHECK-NEXT:    i64.load $push3=, 0($pop2)
; CHECK-NEXT:    i64.store 8($pop16), $pop3
; CHECK-NEXT:    local.get $push18=, 0
; CHECK-NEXT:    local.get $push17=, 5
; CHECK-NEXT:    i64.load $push4=, 0($pop17)
; CHECK-NEXT:    i64.store 0($pop18), $pop4
; CHECK-NEXT:    local.get $push19=, 5
; CHECK-NEXT:    i32.const $push7=, 16
; CHECK-NEXT:    i32.add $push8=, $pop19, $pop7
; CHECK-NEXT:    global.set __stack_pointer, $pop8
; CHECK-NEXT:    return
  %a = ashr i128 %x, %y
  ret i128 %a
}

define i128 @clz128(i128 %x) {
; CHECK-LABEL: clz128:
; CHECK:         .functype clz128 (i32, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push8=, 0
; CHECK-NEXT:    i64.const $push0=, 0
; CHECK-NEXT:    i64.store 8($pop8), $pop0
; CHECK-NEXT:    local.get $push12=, 0
; CHECK-NEXT:    local.get $push9=, 2
; CHECK-NEXT:    i64.clz $push5=, $pop9
; CHECK-NEXT:    local.get $push10=, 1
; CHECK-NEXT:    i64.clz $push2=, $pop10
; CHECK-NEXT:    i64.const $push3=, 64
; CHECK-NEXT:    i64.add $push4=, $pop2, $pop3
; CHECK-NEXT:    local.get $push11=, 2
; CHECK-NEXT:    i64.const $push7=, 0
; CHECK-NEXT:    i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT:    i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT:    i64.store 0($pop12), $pop6
; CHECK-NEXT:    return
  %a = call i128 @llvm.ctlz.i128(i128 %x, i1 false)
  ret i128 %a
}

define i128 @clz128_zero_undef(i128 %x) {
; CHECK-LABEL: clz128_zero_undef:
; CHECK:         .functype clz128_zero_undef (i32, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push8=, 0
; CHECK-NEXT:    i64.const $push0=, 0
; CHECK-NEXT:    i64.store 8($pop8), $pop0
; CHECK-NEXT:    local.get $push12=, 0
; CHECK-NEXT:    local.get $push9=, 2
; CHECK-NEXT:    i64.clz $push5=, $pop9
; CHECK-NEXT:    local.get $push10=, 1
; CHECK-NEXT:    i64.clz $push2=, $pop10
; CHECK-NEXT:    i64.const $push3=, 64
; CHECK-NEXT:    i64.add $push4=, $pop2, $pop3
; CHECK-NEXT:    local.get $push11=, 2
; CHECK-NEXT:    i64.const $push7=, 0
; CHECK-NEXT:    i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT:    i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT:    i64.store 0($pop12), $pop6
; CHECK-NEXT:    return
  %a = call i128 @llvm.ctlz.i128(i128 %x, i1 true)
  ret i128 %a
}

define i128 @ctz128(i128 %x) {
; CHECK-LABEL: ctz128:
; CHECK:         .functype ctz128 (i32, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push8=, 0
; CHECK-NEXT:    i64.const $push0=, 0
; CHECK-NEXT:    i64.store 8($pop8), $pop0
; CHECK-NEXT:    local.get $push12=, 0
; CHECK-NEXT:    local.get $push9=, 1
; CHECK-NEXT:    i64.ctz $push5=, $pop9
; CHECK-NEXT:    local.get $push10=, 2
; CHECK-NEXT:    i64.ctz $push2=, $pop10
; CHECK-NEXT:    i64.const $push3=, 64
; CHECK-NEXT:    i64.add $push4=, $pop2, $pop3
; CHECK-NEXT:    local.get $push11=, 1
; CHECK-NEXT:    i64.const $push7=, 0
; CHECK-NEXT:    i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT:    i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT:    i64.store 0($pop12), $pop6
; CHECK-NEXT:    return
  %a = call i128 @llvm.cttz.i128(i128 %x, i1 false)
  ret i128 %a
}

define i128 @ctz128_zero_undef(i128 %x) {
; CHECK-LABEL: ctz128_zero_undef:
; CHECK:         .functype ctz128_zero_undef (i32, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push8=, 0
; CHECK-NEXT:    i64.const $push0=, 0
; CHECK-NEXT:    i64.store 8($pop8), $pop0
; CHECK-NEXT:    local.get $push12=, 0
; CHECK-NEXT:    local.get $push9=, 1
; CHECK-NEXT:    i64.ctz $push5=, $pop9
; CHECK-NEXT:    local.get $push10=, 2
; CHECK-NEXT:    i64.ctz $push2=, $pop10
; CHECK-NEXT:    i64.const $push3=, 64
; CHECK-NEXT:    i64.add $push4=, $pop2, $pop3
; CHECK-NEXT:    local.get $push11=, 1
; CHECK-NEXT:    i64.const $push7=, 0
; CHECK-NEXT:    i64.ne $push1=, $pop11, $pop7
; CHECK-NEXT:    i64.select $push6=, $pop5, $pop4, $pop1
; CHECK-NEXT:    i64.store 0($pop12), $pop6
; CHECK-NEXT:    return
  %a = call i128 @llvm.cttz.i128(i128 %x, i1 true)
  ret i128 %a
}

define i128 @popcnt128(i128 %x) {
; CHECK-LABEL: popcnt128:
; CHECK:         .functype popcnt128 (i32, i64, i64) -> ()
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push4=, 0
; CHECK-NEXT:    i64.const $push0=, 0
; CHECK-NEXT:    i64.store 8($pop4), $pop0
; CHECK-NEXT:    local.get $push7=, 0
; CHECK-NEXT:    local.get $push5=, 1
; CHECK-NEXT:    i64.popcnt $push2=, $pop5
; CHECK-NEXT:    local.get $push6=, 2
; CHECK-NEXT:    i64.popcnt $push1=, $pop6
; CHECK-NEXT:    i64.add $push3=, $pop2, $pop1
; CHECK-NEXT:    i64.store 0($pop7), $pop3
; CHECK-NEXT:    return
  %a = call i128 @llvm.ctpop.i128(i128 %x)
  ret i128 %a
}

define i32 @eqz128(i128 %x) {
; CHECK-LABEL: eqz128:
; CHECK:         .functype eqz128 (i64, i64) -> (i32)
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    local.get $push3=, 0
; CHECK-NEXT:    local.get $push2=, 1
; CHECK-NEXT:    i64.or $push0=, $pop3, $pop2
; CHECK-NEXT:    i64.eqz $push1=, $pop0
; CHECK-NEXT:    return $pop1
  %a = icmp eq i128 %x, 0
  %b = zext i1 %a to i32
  ret i32 %b
}

define i128 @rotl(i128 %x, i128 %y) {
; CHECK-LABEL: rotl:
; CHECK:         .functype rotl (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32, i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push11=, __stack_pointer
; CHECK-NEXT:    i32.const $push12=, 32
; CHECK-NEXT:    i32.sub $push23=, $pop11, $pop12
; CHECK-NEXT:    local.tee $push22=, 5, $pop23
; CHECK-NEXT:    global.set __stack_pointer, $pop22
; CHECK-NEXT:    local.get $push24=, 5
; CHECK-NEXT:    i32.const $push15=, 16
; CHECK-NEXT:    i32.add $push16=, $pop24, $pop15
; CHECK-NEXT:    local.get $push27=, 1
; CHECK-NEXT:    local.get $push26=, 2
; CHECK-NEXT:    local.get $push25=, 3
; CHECK-NEXT:    i32.wrap_i64 $push21=, $pop25
; CHECK-NEXT:    local.tee $push20=, 6, $pop21
; CHECK-NEXT:    call __ashlti3, $pop16, $pop27, $pop26, $pop20
; CHECK-NEXT:    local.get $push31=, 5
; CHECK-NEXT:    local.get $push30=, 1
; CHECK-NEXT:    local.get $push29=, 2
; CHECK-NEXT:    i32.const $push0=, 128
; CHECK-NEXT:    local.get $push28=, 6
; CHECK-NEXT:    i32.sub $push1=, $pop0, $pop28
; CHECK-NEXT:    call __lshrti3, $pop31, $pop30, $pop29, $pop1
; CHECK-NEXT:    local.get $push34=, 0
; CHECK-NEXT:    local.get $push32=, 5
; CHECK-NEXT:    i32.const $push17=, 16
; CHECK-NEXT:    i32.add $push18=, $pop32, $pop17
; CHECK-NEXT:    i32.const $push2=, 8
; CHECK-NEXT:    i32.add $push3=, $pop18, $pop2
; CHECK-NEXT:    i64.load $push4=, 0($pop3)
; CHECK-NEXT:    local.get $push33=, 5
; CHECK-NEXT:    i32.const $push19=, 8
; CHECK-NEXT:    i32.add $push5=, $pop33, $pop19
; CHECK-NEXT:    i64.load $push6=, 0($pop5)
; CHECK-NEXT:    i64.or $push7=, $pop4, $pop6
; CHECK-NEXT:    i64.store 8($pop34), $pop7
; CHECK-NEXT:    local.get $push37=, 0
; CHECK-NEXT:    local.get $push35=, 5
; CHECK-NEXT:    i64.load $push8=, 16($pop35)
; CHECK-NEXT:    local.get $push36=, 5
; CHECK-NEXT:    i64.load $push9=, 0($pop36)
; CHECK-NEXT:    i64.or $push10=, $pop8, $pop9
; CHECK-NEXT:    i64.store 0($pop37), $pop10
; CHECK-NEXT:    local.get $push38=, 5
; CHECK-NEXT:    i32.const $push13=, 32
; CHECK-NEXT:    i32.add $push14=, $pop38, $pop13
; CHECK-NEXT:    global.set __stack_pointer, $pop14
; CHECK-NEXT:    return
  %z = sub i128 128, %y
  %b = shl i128 %x, %y
  %c = lshr i128 %x, %z
  %d = or i128 %b, %c
  ret i128 %d
}

define i128 @masked_rotl(i128 %x, i128 %y) {
; CHECK-LABEL: masked_rotl:
; CHECK:         .functype masked_rotl (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32, i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push13=, __stack_pointer
; CHECK-NEXT:    i32.const $push14=, 32
; CHECK-NEXT:    i32.sub $push25=, $pop13, $pop14
; CHECK-NEXT:    local.tee $push24=, 5, $pop25
; CHECK-NEXT:    global.set __stack_pointer, $pop24
; CHECK-NEXT:    local.get $push26=, 5
; CHECK-NEXT:    i32.const $push17=, 16
; CHECK-NEXT:    i32.add $push18=, $pop26, $pop17
; CHECK-NEXT:    local.get $push29=, 1
; CHECK-NEXT:    local.get $push28=, 2
; CHECK-NEXT:    local.get $push27=, 3
; CHECK-NEXT:    i32.wrap_i64 $push0=, $pop27
; CHECK-NEXT:    i32.const $push1=, 127
; CHECK-NEXT:    i32.and $push23=, $pop0, $pop1
; CHECK-NEXT:    local.tee $push22=, 6, $pop23
; CHECK-NEXT:    call __ashlti3, $pop18, $pop29, $pop28, $pop22
; CHECK-NEXT:    local.get $push33=, 5
; CHECK-NEXT:    local.get $push32=, 1
; CHECK-NEXT:    local.get $push31=, 2
; CHECK-NEXT:    i32.const $push2=, 128
; CHECK-NEXT:    local.get $push30=, 6
; CHECK-NEXT:    i32.sub $push3=, $pop2, $pop30
; CHECK-NEXT:    call __lshrti3, $pop33, $pop32, $pop31, $pop3
; CHECK-NEXT:    local.get $push36=, 0
; CHECK-NEXT:    local.get $push34=, 5
; CHECK-NEXT:    i32.const $push19=, 16
; CHECK-NEXT:    i32.add $push20=, $pop34, $pop19
; CHECK-NEXT:    i32.const $push4=, 8
; CHECK-NEXT:    i32.add $push5=, $pop20, $pop4
; CHECK-NEXT:    i64.load $push6=, 0($pop5)
; CHECK-NEXT:    local.get $push35=, 5
; CHECK-NEXT:    i32.const $push21=, 8
; CHECK-NEXT:    i32.add $push7=, $pop35, $pop21
; CHECK-NEXT:    i64.load $push8=, 0($pop7)
; CHECK-NEXT:    i64.or $push9=, $pop6, $pop8
; CHECK-NEXT:    i64.store 8($pop36), $pop9
; CHECK-NEXT:    local.get $push39=, 0
; CHECK-NEXT:    local.get $push37=, 5
; CHECK-NEXT:    i64.load $push10=, 16($pop37)
; CHECK-NEXT:    local.get $push38=, 5
; CHECK-NEXT:    i64.load $push11=, 0($pop38)
; CHECK-NEXT:    i64.or $push12=, $pop10, $pop11
; CHECK-NEXT:    i64.store 0($pop39), $pop12
; CHECK-NEXT:    local.get $push40=, 5
; CHECK-NEXT:    i32.const $push15=, 32
; CHECK-NEXT:    i32.add $push16=, $pop40, $pop15
; CHECK-NEXT:    global.set __stack_pointer, $pop16
; CHECK-NEXT:    return
  %a = and i128 %y, 127
  %z = sub i128 128, %a
  %b = shl i128 %x, %a
  %c = lshr i128 %x, %z
  %d = or i128 %b, %c
  ret i128 %d
}

define i128 @rotr(i128 %x, i128 %y) {
; CHECK-LABEL: rotr:
; CHECK:         .functype rotr (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32, i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push11=, __stack_pointer
; CHECK-NEXT:    i32.const $push12=, 32
; CHECK-NEXT:    i32.sub $push23=, $pop11, $pop12
; CHECK-NEXT:    local.tee $push22=, 5, $pop23
; CHECK-NEXT:    global.set __stack_pointer, $pop22
; CHECK-NEXT:    local.get $push24=, 5
; CHECK-NEXT:    i32.const $push15=, 16
; CHECK-NEXT:    i32.add $push16=, $pop24, $pop15
; CHECK-NEXT:    local.get $push27=, 1
; CHECK-NEXT:    local.get $push26=, 2
; CHECK-NEXT:    local.get $push25=, 3
; CHECK-NEXT:    i32.wrap_i64 $push21=, $pop25
; CHECK-NEXT:    local.tee $push20=, 6, $pop21
; CHECK-NEXT:    call __lshrti3, $pop16, $pop27, $pop26, $pop20
; CHECK-NEXT:    local.get $push31=, 5
; CHECK-NEXT:    local.get $push30=, 1
; CHECK-NEXT:    local.get $push29=, 2
; CHECK-NEXT:    i32.const $push0=, 128
; CHECK-NEXT:    local.get $push28=, 6
; CHECK-NEXT:    i32.sub $push1=, $pop0, $pop28
; CHECK-NEXT:    call __ashlti3, $pop31, $pop30, $pop29, $pop1
; CHECK-NEXT:    local.get $push34=, 0
; CHECK-NEXT:    local.get $push32=, 5
; CHECK-NEXT:    i32.const $push17=, 16
; CHECK-NEXT:    i32.add $push18=, $pop32, $pop17
; CHECK-NEXT:    i32.const $push2=, 8
; CHECK-NEXT:    i32.add $push3=, $pop18, $pop2
; CHECK-NEXT:    i64.load $push4=, 0($pop3)
; CHECK-NEXT:    local.get $push33=, 5
; CHECK-NEXT:    i32.const $push19=, 8
; CHECK-NEXT:    i32.add $push5=, $pop33, $pop19
; CHECK-NEXT:    i64.load $push6=, 0($pop5)
; CHECK-NEXT:    i64.or $push7=, $pop4, $pop6
; CHECK-NEXT:    i64.store 8($pop34), $pop7
; CHECK-NEXT:    local.get $push37=, 0
; CHECK-NEXT:    local.get $push35=, 5
; CHECK-NEXT:    i64.load $push8=, 16($pop35)
; CHECK-NEXT:    local.get $push36=, 5
; CHECK-NEXT:    i64.load $push9=, 0($pop36)
; CHECK-NEXT:    i64.or $push10=, $pop8, $pop9
; CHECK-NEXT:    i64.store 0($pop37), $pop10
; CHECK-NEXT:    local.get $push38=, 5
; CHECK-NEXT:    i32.const $push13=, 32
; CHECK-NEXT:    i32.add $push14=, $pop38, $pop13
; CHECK-NEXT:    global.set __stack_pointer, $pop14
; CHECK-NEXT:    return
  %z = sub i128 128, %y
  %b = lshr i128 %x, %y
  %c = shl i128 %x, %z
  %d = or i128 %b, %c
  ret i128 %d
}

define i128 @masked_rotr(i128 %x, i128 %y) {
; CHECK-LABEL: masked_rotr:
; CHECK:         .functype masked_rotr (i32, i64, i64, i64, i64) -> ()
; CHECK-NEXT:    .local i32, i32
; CHECK-NEXT:  # %bb.0:
; CHECK-NEXT:    global.get $push13=, __stack_pointer
; CHECK-NEXT:    i32.const $push14=, 32
; CHECK-NEXT:    i32.sub $push25=, $pop13, $pop14
; CHECK-NEXT:    local.tee $push24=, 5, $pop25
; CHECK-NEXT:    global.set __stack_pointer, $pop24
; CHECK-NEXT:    local.get $push26=, 5
; CHECK-NEXT:    i32.const $push17=, 16
; CHECK-NEXT:    i32.add $push18=, $pop26, $pop17
; CHECK-NEXT:    local.get $push29=, 1
; CHECK-NEXT:    local.get $push28=, 2
; CHECK-NEXT:    local.get $push27=, 3
; CHECK-NEXT:    i32.wrap_i64 $push0=, $pop27
; CHECK-NEXT:    i32.const $push1=, 127
; CHECK-NEXT:    i32.and $push23=, $pop0, $pop1
; CHECK-NEXT:    local.tee $push22=, 6, $pop23
; CHECK-NEXT:    call __lshrti3, $pop18, $pop29, $pop28, $pop22
; CHECK-NEXT:    local.get $push33=, 5
; CHECK-NEXT:    local.get $push32=, 1
; CHECK-NEXT:    local.get $push31=, 2
; CHECK-NEXT:    i32.const $push2=, 128
; CHECK-NEXT:    local.get $push30=, 6
; CHECK-NEXT:    i32.sub $push3=, $pop2, $pop30
; CHECK-NEXT:    call __ashlti3, $pop33, $pop32, $pop31, $pop3
; CHECK-NEXT:    local.get $push36=, 0
; CHECK-NEXT:    local.get $push34=, 5
; CHECK-NEXT:    i32.const $push19=, 16
; CHECK-NEXT:    i32.add $push20=, $pop34, $pop19
; CHECK-NEXT:    i32.const $push4=, 8
; CHECK-NEXT:    i32.add $push5=, $pop20, $pop4
; CHECK-NEXT:    i64.load $push6=, 0($pop5)
; CHECK-NEXT:    local.get $push35=, 5
; CHECK-NEXT:    i32.const $push21=, 8
; CHECK-NEXT:    i32.add $push7=, $pop35, $pop21
; CHECK-NEXT:    i64.load $push8=, 0($pop7)
; CHECK-NEXT:    i64.or $push9=, $pop6, $pop8
; CHECK-NEXT:    i64.store 8($pop36), $pop9
; CHECK-NEXT:    local.get $push39=, 0
; CHECK-NEXT:    local.get $push37=, 5
; CHECK-NEXT:    i64.load $push10=, 16($pop37)
; CHECK-NEXT:    local.get $push38=, 5
; CHECK-NEXT:    i64.load $push11=, 0($pop38)
; CHECK-NEXT:    i64.or $push12=, $pop10, $pop11
; CHECK-NEXT:    i64.store 0($pop39), $pop12
; CHECK-NEXT:    local.get $push40=, 5
; CHECK-NEXT:    i32.const $push15=, 32
; CHECK-NEXT:    i32.add $push16=, $pop40, $pop15
; CHECK-NEXT:    global.set __stack_pointer, $pop16
; CHECK-NEXT:    return
  %a = and i128 %y, 127
  %z = sub i128 128, %a
  %b = lshr i128 %x, %a
  %c = shl i128 %x, %z
  %d = or i128 %b, %c
  ret i128 %d
}
